const puppeteer = require('puppeteer-cn');
const path = require('path');
const fs = require('fs-extra');
const crypto = require('crypto');
const URL = require('url').URL;
const rootPath = path.join(__dirname, '/public/map');

function getMd5Path(query) {
    const hash = crypto.createHash('md5');
    return hash.update(query, 'utf-8').digest('hex')+'.png';
}
async function getResourceContent(page, url) {
    const data = await page._client.send(
        'Page.getResourceContent',
        { frameId: String(page.mainFrame()._id), url },
    );
    return data.base64Encoded ? Buffer.from(data.content, 'base64') : data.content;
};
async function getResourceTree(page) {
    const resource = await page._client.send('Page.getResourceTree');
    const { resources } = resource.frameTree;
    for (const o of resources) {
        if (o.type === 'Image') {
            const url = new URL(o.url);
            if (url.search) {
                const image = path.join(rootPath, url.pathname, getMd5Path(url.search));
                if (fs.existsSync(image)) {
                    console.log('========[exists]=========: image = ', image);
                } else {
                    console.log('[saved]: image = ', image);
                    fs.ensureFileSync(image);
                    const buffer = await getResourceContent(page, o.url);
                    fs.writeFileSync(image, buffer);
                }
            }
        } else {
            console.log("=======", o.url);
        }
    }
}
async function saveRect(zoom, center, width, height) {
    console.log(`[start]: zoom=${zoom},center=${center.join(',')},width=${width},height=${height}`);
    const browser = await puppeteer.launch();
    const page = await browser.newPage();
    await page.setViewport({ width, height });
    await page.goto(`http://localhost:4000?zoom=${zoom}&center=${center.join(',')}`);
    await page.waitForTimeout(5000);
    await getResourceTree(page);
    await browser.close();
}
// 像素转纬度（latitude）
function unitToLat(size, zoom, lat) {
    return -1 * size * 360/(256*Math.pow(2,zoom))*Math.cos(lat/180*Math.PI);
}
// 像素转经度（longitude）
function unitToLng(size, zoom) {
    return size * 360/(256*Math.pow(2,zoom));
}
// 经纬度的点在zoom层级时x,y的偏移下的最终经纬度的点
function PointTranslate(lng0, lat0, x, y, zoom) {
    var lng = lng0 + unitToLng(x, zoom);
    var lat1 = lat0 + unitToLat(y, zoom, lat0);
    var lat = lat0 + unitToLat(y, zoom, (lat1 + lat0)/2);
    return [ lng, lat ];
}
async function saveLayer(zoom, centerList, width, height) {
    const _centerList = [];
    for (const center of centerList) {
        await saveRect(zoom, center, width, height);
        _centerList.push(PointTranslate(center[0], center[1], -width/2, -height/2, zoom));
        _centerList.push(PointTranslate(center[0], center[1], width/2, -height/2, zoom));
        _centerList.push(PointTranslate(center[0], center[1], -width/2, height/2, zoom));
        _centerList.push(PointTranslate(center[0], center[1], width/2, height/2, zoom));
    }
    zoom < 13 && await saveLayer(zoom+1, _centerList, width, height);
}

saveLayer(10, [[106.76995,25.97901]], 1000, 1000);
